package com.suifeng.mq.stock.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.suifeng.mq.common.constants.LockConstant;
import com.suifeng.mq.common.enums.OrderStatusEnum;
import com.suifeng.mq.common.exception.NoStockException;
import com.suifeng.mq.common.to.OrderTo;
import com.suifeng.mq.common.to.StockDetailTo;
import com.suifeng.mq.common.to.StockLockedTo;
import com.suifeng.mq.common.utils.R;
import com.suifeng.mq.common.vo.OrderItemVo;
import com.suifeng.mq.common.vo.OrderVo;
import com.suifeng.mq.common.vo.StockGoodsLockVo;
import com.suifeng.mq.stock.dao.StockDao;
import com.suifeng.mq.stock.entity.StockEntity;
import com.suifeng.mq.stock.entity.StockOrderTaskDetailEntity;
import com.suifeng.mq.stock.entity.StockOrderTaskEntity;
import com.suifeng.mq.stock.feign.OrderFeignService;
import com.suifeng.mq.stock.service.StockOrderTaskDetailService;
import com.suifeng.mq.stock.service.StockOrderTaskService;
import com.suifeng.mq.stock.service.StockService;
import com.suifeng.mq.stock.vo.HasGoodsStockVo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class StockServiceImpl extends ServiceImpl<StockDao, StockEntity> implements StockService {

    @Autowired
    private StockOrderTaskService orderTaskService;

    @Autowired
    private StockOrderTaskDetailService stockOrderTaskDetailService;

    @Autowired
    private StockDao stockDao;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private OrderFeignService orderFeignService;

    @Transactional(rollbackFor = NoStockException.class)
    @Override
    public Boolean orderLockStock(StockGoodsLockVo lockVo) {

        //保存库存工作单的详情
        StockOrderTaskEntity taskEntity = new StockOrderTaskEntity();
        taskEntity.setOrderSn(lockVo.getOrderSn());
        orderTaskService.save(taskEntity);

        //1.找到每个商品在哪个仓库都有库存

        List<OrderItemVo> locks = lockVo.getLocks();

        List<HasGoodsStockVo> collect = locks.stream().map(item -> {
            HasGoodsStockVo hasGoodsStockVo = new HasGoodsStockVo();
            Long goodsId = item.getGoodsId();
            hasGoodsStockVo.setGoodsId(goodsId);
            hasGoodsStockVo.setGoodsName(item.getGoodsName());
            hasGoodsStockVo.setNum(item.getGoodsNum());
            //查询这个商品在哪里有库存
            List<Long> stockIds = stockDao.listStockIdHasGoodsStock(goodsId);
            hasGoodsStockVo.setStockIds(stockIds);
            return hasGoodsStockVo;
        }).collect(Collectors.toList());

        //2.锁定库存
        for (HasGoodsStockVo hasStock : collect) {
            Boolean skuStocked = false;
            Long goodsId = hasStock.getGoodsId();
            List<Long> stockIds = hasStock.getStockIds();

            if (CollectionUtils.isEmpty(stockIds)) {
                //没有任何仓库有这个商品的库存
                throw new NoStockException(goodsId);
            }

            //1.如果每一个商品 都锁定成功，将当前商品锁定了几件的工作单记录发给MQ
            //2.锁定失败。前面保存的工作单信息就回滚了。发送出去的消息，即使要解锁记录，由于去数据库查不到id,所以就不用解锁
            for (Long stockId : stockIds) {
                //成功返回1 失败返回0
                Long count = stockDao.lockGoodsStock(goodsId, stockId, hasStock.getNum());

                if (count == 1) {
                    skuStocked = true;
                    //TODO 告诉MQ锁定成功
                    StockOrderTaskDetailEntity detailEntity = new StockOrderTaskDetailEntity(null, goodsId, hasStock.getGoodsName(), hasStock.getNum(), taskEntity.getId(), stockId, 1);
                    stockOrderTaskDetailService.save(detailEntity);
                    StockLockedTo lockedTo = new StockLockedTo();
                    lockedTo.setId(taskEntity.getId());
                    StockDetailTo stockDetailTo = new StockDetailTo();
                    BeanUtils.copyProperties(detailEntity, stockDetailTo);
                    lockedTo.setDetail(stockDetailTo);
                    rabbitTemplate.convertAndSend("stock-event-exchange", "stock.locked", lockedTo);
                    break;
                } else {
                    //当前仓库锁失败，重试下一个仓库
                }

            }

            if (skuStocked == false) {
                //当前商品所有仓库都没有锁住
                throw new NoStockException(goodsId);
            }
        }

        //走到这，说明肯定全部是锁定成功
        return true;
    }


    private void unLockStock(Long skuId, Long wareId, Integer num, Long taskDetailId) {
        stockDao.unLockStock(skuId, wareId, num);
        //更新库存工作单的状态
        StockOrderTaskDetailEntity entity = new StockOrderTaskDetailEntity();
        entity.setId(taskDetailId);
        //设置为已解锁
        entity.setLockStatus(LockConstant.HAS_UNLOCKED);
        stockOrderTaskDetailService.updateById(entity);
    }

    @Override
    public void unlockStock(StockLockedTo to) {
        StockDetailTo detail = to.getDetail();
        Long detailId = detail.getId();
        /**
         * 解锁
         * 1.查询数据库关于这个订单的锁定库存信息
         * 有: 说明库存锁定成功了
         *      解锁： 订单情况。
         *          1.没有这个订单，必须解锁
         *          2.有这个订单，不是解锁库存
         *              查看订单状态：已取消-->解锁库存
         *                            没取消-->不能解锁
         * 没有：库存锁定失败了，库存回滚了，这种情况无需解锁
         */

        StockOrderTaskDetailEntity stockDetail = stockOrderTaskDetailService.getById(detailId);
        if (stockDetail != null) {
            //解锁
            Long id = to.getId();
            StockOrderTaskEntity taskEntity = orderTaskService.getById(id);
            String orderSn = taskEntity.getOrderSn();
            R r = orderFeignService.getOrderStatus(orderSn);
            if (r.getCode() == 0) {
                //订单数据返回成功
                OrderVo data = r.getData(new TypeReference<OrderVo>() {
                });
                if (data == null || data.getStatus() == OrderStatusEnum.CANCLED.getCode()) {
                    //订单不存在或者订单已经被取消了。都要解锁库存
                    if (stockDetail.getLockStatus() == LockConstant.HAS_LOCKED) {
                        //只有未解锁状态的才需要解锁，防止重复解锁   状态1-已锁定，但未解锁才可以解锁
                        unLockStock(detail.getGoodsId(), detail.getStockId(), detail.getGoodsNum(), detailId);
                    }
                }
            } else {
                //消息拒绝以后重新回到队列里面，让别人继续消费解锁
                throw new RuntimeException("远程服务失败");
            }
        } else {
            //无需解锁(库存自己失败回滚无须解锁)
        }
    }

    /**
     * 防止订单服务卡顿，导致订单状态消息一直改不了，然后库存消息优先到期
     * 查看订单状态仍是新建状态，什么都不做就走了，这样会导致卡顿的订单
     * 永远无法解锁库存
     *
     * @param orderTo
     */
    @Override
    @Transactional
    public void unlockStock(OrderTo orderTo) {

        String orderSn = orderTo.getOrderSn();
        //查一下最新库存的状态，防止重复解锁库存
        StockOrderTaskEntity task = orderTaskService.getStockOrderTaskByOrderSn(orderSn);
        Long id = task.getId();
        //按照工作单id找到所有没有解锁的库存进行解锁
        List<StockOrderTaskDetailEntity> list = stockOrderTaskDetailService.list(new LambdaQueryWrapper<StockOrderTaskDetailEntity>()
                .eq(StockOrderTaskDetailEntity::getTaskId, id)
                .eq(StockOrderTaskDetailEntity::getLockStatus, LockConstant.HAS_LOCKED));
        for (StockOrderTaskDetailEntity entity : list) {
            unLockStock(entity.getGoodsId(), entity.getStockId(), entity.getGoodsNum(), entity.getId());
        }

    }


}
